package com.smartinput.voice.application.service

import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.io.File
import java.util.*
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import kotlin.concurrent.thread

/**
 * 实时语音识别自动测试服务
 * 
 * 功能：
 * 1. 加载测试音频文件
 * 2. 模拟实时音频流发送
 * 3. 验证识别结果
 * 4. 生成测试报告
 */
@Service
class VoiceRecognitionTestService {

    @Autowired
    private lateinit var aliyunWebSocketService: AliyunWebSocketSpeechRecognitionService
    
    private val logger = LoggerFactory.getLogger(VoiceRecognitionTestService::class.java)
    
    /**
     * 测试结果数据类
     */
    data class TestResult(
        val testId: String,
        val audioFile: String,
        val expectedText: String,
        val actualText: String,
        val confidence: Double,
        val success: Boolean,
        val errorMessage: String?,
        val duration: Long, // 测试用时（毫秒）
        val audioSize: Long, // 音频文件大小
        val audioLength: Double // 音频时长（秒）
    )
    
    /**
     * 测试配置数据类
     */
    data class TestConfig(
        val audioFile: String,
        val expectedText: String,
        val chunkSize: Int = 3200, // 每次发送的音频数据大小
        val intervalMs: Long = 200, // 发送间隔（毫秒）
        val timeoutSeconds: Int = 30 // 超时时间（秒）
    )
    
    /**
     * 执行单个音频文件的测试
     */
    fun runSingleTest(config: TestConfig): TestResult {
        val testId = UUID.randomUUID().toString()
        val startTime = System.currentTimeMillis()
        
        logger.info("🧪 开始语音识别测试")
        logger.info("   测试ID: $testId")
        logger.info("   音频文件: ${config.audioFile}")
        logger.info("   期望文本: ${config.expectedText}")
        logger.info("   块大小: ${config.chunkSize} bytes")
        logger.info("   发送间隔: ${config.intervalMs} ms")
        
        return try {
            // 1. 验证音频文件存在
            val audioFile = File(config.audioFile)
            if (!audioFile.exists()) {
                return TestResult(
                    testId = testId,
                    audioFile = config.audioFile,
                    expectedText = config.expectedText,
                    actualText = "",
                    confidence = 0.0,
                    success = false,
                    errorMessage = "音频文件不存在: ${config.audioFile}",
                    duration = System.currentTimeMillis() - startTime,
                    audioSize = 0,
                    audioLength = 0.0
                )
            }
            
            val audioData = audioFile.readBytes()
            val audioLength = calculateAudioLength(audioData)
            
            logger.info("✅ 音频文件加载成功: ${audioData.size} bytes, ${String.format("%.2f", audioLength)}秒")
            
            // 2. 设置识别结果收集器
            val resultCollector = TestResultCollector()
            
            // 3. 创建测试会话
            val traceId = "test_$testId"
            aliyunWebSocketService.setRecognitionResultCallback(traceId) { result ->
                resultCollector.addResult(result.text, result.confidence)
                if (result.text.isNotBlank()) {
                    logger.info("📝 收到识别结果: ${result.text} (置信度: ${result.confidence})")
                }
            }
            
            // 4. 模拟实时音频流发送
            simulateRealTimeAudioStream(traceId, audioData, config)
            
            // 5. 等待识别完成
            val finalResult = resultCollector.waitForFinalResult(config.timeoutSeconds)
            
            // 6. 停止会话
            aliyunWebSocketService.stopCurrentSession(traceId)
            
            val endTime = System.currentTimeMillis()
            val duration = endTime - startTime
            
            // 7. 生成测试结果
            val testResult = TestResult(
                testId = testId,
                audioFile = config.audioFile,
                expectedText = config.expectedText,
                actualText = finalResult.text,
                confidence = finalResult.confidence,
                success = isTextMatch(config.expectedText, finalResult.text),
                errorMessage = finalResult.errorMessage,
                duration = duration,
                audioSize = audioData.size.toLong(),
                audioLength = audioLength
            )
            
            logTestResult(testResult)
            testResult
            
        } catch (e: Exception) {
            logger.error("测试执行失败", e)
            TestResult(
                testId = testId,
                audioFile = config.audioFile,
                expectedText = config.expectedText,
                actualText = "",
                confidence = 0.0,
                success = false,
                errorMessage = e.message,
                duration = System.currentTimeMillis() - startTime,
                audioSize = 0,
                audioLength = 0.0
            )
        }
    }
    
    /**
     * 模拟实时音频流发送
     */
    private fun simulateRealTimeAudioStream(traceId: String, audioData: ByteArray, config: TestConfig) {
        logger.info("🎵 开始模拟实时音频流发送")
        
        // 跳过WAV文件头（如果存在）
        val audioStart = if (audioData.size > 44 && 
                            audioData.sliceArray(0..3).contentEquals("RIFF".toByteArray()) &&
                            audioData.sliceArray(8..11).contentEquals("WAVE".toByteArray())) {
            44
        } else {
            0
        }
        
        val pcmData = audioData.sliceArray(audioStart until audioData.size)
        logger.info("📊 音频数据处理: 原始${audioData.size}bytes, PCM${pcmData.size}bytes")
        
        var offset = 0
        var chunkCount = 0
        
        // 分块发送音频数据，模拟实时语音流
        while (offset < pcmData.size) {
            val remainingSize = pcmData.size - offset
            val currentChunkSize = minOf(config.chunkSize, remainingSize)
            
            val audioChunk = pcmData.sliceArray(offset until offset + currentChunkSize)
            
            // 发送音频数据
            val result = aliyunWebSocketService.sendAudioData(traceId, audioChunk)
            
            chunkCount++
            offset += currentChunkSize
            
            logger.debug("📤 发送音频块 #$chunkCount: ${audioChunk.size}bytes, 剩余${pcmData.size - offset}bytes")
            
            if (!result.success) {
                logger.warn("⚠️ 音频块发送失败: ${result.error}")
            }
            
            // 模拟实时发送间隔
            if (offset < pcmData.size) {
                Thread.sleep(config.intervalMs)
            }
        }
        
        logger.info("✅ 音频流发送完成: 总共${chunkCount}个块, ${pcmData.size}bytes")
        
        // 发送停止指令
        Thread.sleep(500) // 等待一下再停止
        aliyunWebSocketService.stopCurrentSession(traceId)
        logger.info("🛑 已发送停止识别指令")
    }
    
    /**
     * 计算音频长度（秒）
     */
    private fun calculateAudioLength(audioData: ByteArray): Double {
        // 假设16KHz, 16bit, 单声道PCM格式
        val bytesPerSecond = 16000 * 2 // 16000采样率 * 2字节
        val audioStart = if (audioData.size > 44) 44 else 0 // 跳过WAV头部
        val pcmSize = audioData.size - audioStart
        return pcmSize.toDouble() / bytesPerSecond
    }
    
    /**
     * 检查文本匹配度
     */
    private fun isTextMatch(expected: String, actual: String): Boolean {
        if (expected.isBlank() && actual.isBlank()) return true
        if (expected.isBlank() || actual.isBlank()) return false
        
        // 简单的文本匹配检查（去除标点和空格，转换为小写）
        val normalizedExpected = expected.replace(Regex("[\\p{Punct}\\s]"), "").lowercase()
        val normalizedActual = actual.replace(Regex("[\\p{Punct}\\s]"), "").lowercase()
        
        // 计算相似度
        val similarity = calculateSimilarity(normalizedExpected, normalizedActual)
        return similarity > 0.8 // 80%相似度认为匹配
    }
    
    /**
     * 计算字符串相似度（简单的编辑距离算法）
     */
    private fun calculateSimilarity(s1: String, s2: String): Double {
        val maxLen = maxOf(s1.length, s2.length)
        if (maxLen == 0) return 1.0
        
        val distance = editDistance(s1, s2)
        return (maxLen - distance).toDouble() / maxLen
    }
    
    private fun editDistance(s1: String, s2: String): Int {
        val m = s1.length
        val n = s2.length
        val dp = Array(m + 1) { IntArray(n + 1) }
        
        for (i in 0..m) dp[i][0] = i
        for (j in 0..n) dp[0][j] = j
        
        for (i in 1..m) {
            for (j in 1..n) {
                if (s1[i - 1] == s2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1]
                } else {
                    dp[i][j] = 1 + minOf(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1])
                }
            }
        }
        
        return dp[m][n]
    }
    
    /**
     * 记录测试结果
     */
    private fun logTestResult(result: TestResult) {
        logger.info("📊 测试结果报告:")
        logger.info("   测试ID: ${result.testId}")
        logger.info("   音频文件: ${result.audioFile}")
        logger.info("   音频大小: ${result.audioSize} bytes")
        logger.info("   音频时长: ${String.format("%.2f", result.audioLength)} 秒")
        logger.info("   期望文本: ${result.expectedText}")
        logger.info("   识别文本: ${result.actualText}")
        logger.info("   置信度: ${String.format("%.2f", result.confidence)}")
        logger.info("   测试结果: ${if (result.success) "✅ 成功" else "❌ 失败"}")
        logger.info("   测试用时: ${result.duration} ms")
        
        if (!result.success && result.errorMessage != null) {
            logger.error("   错误信息: ${result.errorMessage}")
        }
    }
    
    /**
     * 识别结果收集器
     */
    private class TestResultCollector {
        private var finalText = ""
        private var finalConfidence = 0.0
        private var errorMessage: String? = null
        private val latch = CountDownLatch(1)
        private var hasResult = false
        
        fun addResult(text: String, confidence: Double) {
            if (text.isNotBlank()) {
                finalText = text
                finalConfidence = confidence
                hasResult = true
                // 不立即完成，等待最终结果或超时
            }
        }
        
        fun waitForFinalResult(timeoutSeconds: Int): FinalResult {
            return try {
                // 等待一段时间收集更多结果
                Thread.sleep(3000) // 等待3秒收集结果
                
                FinalResult(finalText, finalConfidence, errorMessage)
            } catch (e: Exception) {
                FinalResult("", 0.0, e.message)
            }
        }
        
        data class FinalResult(
            val text: String,
            val confidence: Double,
            val errorMessage: String?
        )
    }
}
